namespace FIREFLYX {
    /** 纹理UV超出处理模式 */
    export enum TexWrapMode {
        REPEAT,
        CLAMP,
        MIRRORED
    }

    /** 各项异性 等级 */
    export enum AnisotropicLevel {
        OFF = 1,
        X2 = 2,
        X4 = 4,
        X8 = 8,
        X16 = 16
    }

    /** 纹理格式 (对齐webgl internalformat )*/
    export enum TextureFormat {
        RGBA = WebGL2RenderingContext.RGBA,
        RGB = WebGL2RenderingContext.RGB,
        LUMINANCE_ALPHA = WebGL2RenderingContext.LUMINANCE_ALPHA,
        LUMINANCE = WebGL2RenderingContext.LUMINANCE,
        ALPHA = WebGL2RenderingContext.ALPHA,
        DEPTH_COMPONENT32F = WebGL2RenderingContext.DEPTH_COMPONENT32F,
        DEPTH_COMPONENT24 = WebGL2RenderingContext.DEPTH_COMPONENT24,
        DEPTH_COMPONENT16 = WebGL2RenderingContext.DEPTH_COMPONENT16,
        DEPTH24_STENCIL8 = WebGL2RenderingContext.DEPTH24_STENCIL8,
        DEPTH32F_STENCIL8 = WebGL2RenderingContext.DEPTH32F_STENCIL8,
        STENCIL_INDEX8 = WebGL2RenderingContext.STENCIL_INDEX8,
        RGBA4 = WebGL2RenderingContext.RGBA4,
        RGB5_A1 = WebGL2RenderingContext.RGB5_A1,
        RGB10_A2 = WebGL2RenderingContext.RGB10_A2,
        RGBA16F = WebGL2RenderingContext.RGBA16F,
        RGBA32F = WebGL2RenderingContext.RGBA32F,
        RGB565 = WebGL2RenderingContext.RGB565,
        RGB16F = WebGL2RenderingContext.RGB16F,
        RGB32F = WebGL2RenderingContext.RGB32F,
        R16F = WebGL2RenderingContext.R16F,
        R32F = WebGL2RenderingContext.R32F,
    }

    /**
     * 纹理 参数设置
     */
    export class TextureParamSetting {
        /** 线性滤波 （纹理采样是否线性）*/
        public linear: boolean;
        /** 开启mipmap */
        public mipmap: boolean;
        /** 线性mipmap (mipmap 的过程是否线性) */
        public linearMipmap: boolean;
        /** 纹素的数据类型 (可能的值 UNSIGNED_BYTE 、FLOAT) */
        public texelType: GLenum;
        /** 纹理U轴 超出处理模式 */
        public warpU: TexWrapMode;
        /** 纹理V轴 超出处理模式 */
        public warpV: TexWrapMode;
        /** 纹理预乘透明值 */
        public premultiplyAlpha: boolean;
        /** 纹理Y轴翻转 */
        public flipY: boolean;
        /** mipmap 最小开始级别 */
        public mipmapBaseLevel: number;
        /** mipmap 最大开始级别 */
        public mipmapMaxLevel: number;
        /** 各项异性值 */
        public anisotropic: AnisotropicLevel;
        /** 纹理格式 */
        public format: TextureFormat;
        // /** 各项异性滤波级别 */
        // public anisoLevel: number = 0;

        /**
         * 构造 纹理 参数设置
         * @param texelType 纹素的数据类型 ,默认值 UNSIGNED_BYTE (可能的值 UNSIGNED_BYTE 、FLOAT)
         * @param format 纹理格式 ,默认值 RGBA
         * @param linear 线性滤波 ,默认值 true
         * @param mipmap 开启mipmap ,默认值 false
         * @param warpU 纹理U轴 超出处理模式 ,默认值 REPEAT
         * @param warpV 纹理V轴 超出处理模式 ,默认值 REPEAT
         * @param flipY 纹理Y轴翻转 ,默认值 false
         * @param premultiplyAlpha 纹理预乘透明值 ,默认值 false
         * @param mipmapBaseLevel mipmap 最小开始级别 ,默认值 0
         * @param mipmapMaxLevel mipmap 最大开始级别 ,默认值 9
         */
        constructor(
            texelType: GLenum = WebGL2RenderingContext.UNSIGNED_BYTE,
            format: TextureFormat = TextureFormat.RGBA,
            linear: boolean = true,
            linearMipmap: boolean = true,
            mipmap: boolean = false,
            warpU: TexWrapMode = TexWrapMode.REPEAT,
            warpV: TexWrapMode = TexWrapMode.REPEAT,
            flipY: boolean = false,
            premultiplyAlpha: boolean = false,
            mipmapBaseLevel: number = 0,
            mipmapMaxLevel: number = 9,
            anisotropic: AnisotropicLevel = AnisotropicLevel.OFF,
        ) {
            this.texelType = texelType;
            this.format = format;
            this.linear = linear;
            this.linearMipmap = linearMipmap;
            this.mipmap = mipmap;
            this.warpU = warpU;
            this.warpV = warpV;
            this.flipY = flipY;
            this.premultiplyAlpha = premultiplyAlpha;
            this.mipmapBaseLevel = mipmapBaseLevel;
            this.mipmapMaxLevel = mipmapMaxLevel;
            this.anisotropic = anisotropic;
        }

        /**
         * 获取webgl 格式
         * @param glFormat webgl格式数据 
         */
        public getGLFormat(): GLenum {
            const gl = App.webgl2;
            let format: number;
            switch (this.format) {
                case TextureFormat.RGB565:
                case TextureFormat.RGB16F:
                case TextureFormat.RGB32F:
                case TextureFormat.RGB: format = gl.RGB; break;
                case TextureFormat.LUMINANCE_ALPHA: format = gl.LUMINANCE_ALPHA; break;
                case TextureFormat.ALPHA: format = gl.ALPHA; break;
                case TextureFormat.LUMINANCE: format = gl.LUMINANCE; break;
                case TextureFormat.R16F:
                case TextureFormat.R32F: format = gl.RED; break;
                case TextureFormat.DEPTH_COMPONENT16:
                case TextureFormat.DEPTH_COMPONENT24:
                case TextureFormat.DEPTH_COMPONENT32F: format = gl.DEPTH_COMPONENT; break;
                case TextureFormat.DEPTH24_STENCIL8:
                case TextureFormat.DEPTH32F_STENCIL8: format = gl.DEPTH_STENCIL; break;
                case TextureFormat.STENCIL_INDEX8: format = gl.STENCIL; break;
                default: format = gl.RGBA;
            }
            return format;
        }

        /**
         * 获取webgl warp 值
         * @param mode TexWrapMode 
         */
        private static getGLWRAP(mode: TexWrapMode) {
            let gl = App.webgl2;
            switch (mode) {
                case TexWrapMode.REPEAT: return gl.REPEAT;
                case TexWrapMode.CLAMP: return gl.CLAMP_TO_EDGE;
                case TexWrapMode.MIRRORED: return gl.MIRRORED_REPEAT;
                default: return gl.CLAMP_TO_EDGE;
            }
        }

        /**
         * webgl纹理 TEXTURE_2D 应用参数设置
         * @param texTarget 
         * @param glTexture 
         * @param texParam 
         */
        private static apply2DBase(texTarget: GLenum, glTexture: WebGLTexture, texParam: TextureParamSetting) {
            let gl = App.webgl2;
            //绑定指定纹理对象
            gl.bindTexture(texTarget, glTexture);

            //gen mipmap
            if (texParam.mipmap) { gl.generateMipmap(texTarget); }

            //滤波设置
            let magFilter: number = texParam.linear ? gl.LINEAR : gl.NEAREST;
            let minFilter: number;
            if (texParam.mipmap) {
                if (texParam.linearMipmap) {
                    minFilter = texParam.linear ? gl.LINEAR_MIPMAP_LINEAR : gl.NEAREST_MIPMAP_LINEAR;
                } else {
                    minFilter = texParam.linear ? gl.LINEAR_MIPMAP_NEAREST : gl.NEAREST_MIPMAP_NEAREST;
                }
            } else {
                minFilter = (texParam.linear ? gl.LINEAR : gl.NEAREST);
            }

            gl.texParameteri(texTarget, gl.TEXTURE_MAG_FILTER, magFilter);
            gl.texParameteri(texTarget, gl.TEXTURE_MIN_FILTER, minFilter);

            //各项异性
            const anisotropicExt = WebglCapability.EXT_texture_filter_anisotropic;
            if (anisotropicExt) {
                const max = gl.getParameter(anisotropicExt.MAX_TEXTURE_MAX_ANISOTROPY_EXT);
                const val = isNaN(texParam.anisotropic) || texParam.anisotropic < 1 ? AnisotropicLevel.OFF : texParam.anisotropic;
                gl.texParameterf(texTarget, anisotropicExt.TEXTURE_MAX_ANISOTROPY_EXT, val > max ? max : val);
            }

            //纹理UV超出处理
            let wrapS: number = this.getGLWRAP(texParam.warpU);
            let wrapT: number = this.getGLWRAP(texParam.warpV);
            gl.texParameteri(texTarget, gl.TEXTURE_WRAP_S, wrapS);
            gl.texParameteri(texTarget, gl.TEXTURE_WRAP_T, wrapT);

            //解除绑定
            gl.bindTexture(texTarget, null);
        }

        /**
         * webgl纹理 应用参数设置
         * @param texTarget 纹理target  (可能的值 TEXTURE_2D、TEXTURE_CUBE_MAP、TEXTURE_3D、TEXTURE_2D_ARRAY)
         * @param glTexture webgl纹理对象
         * @param texParam 纹理参数设置
         */
        public static applyTex(texTarget: GLenum, glTexture: WebGLTexture, texParam: TextureParamSetting) {
            switch (texTarget) {
                case WebGL2RenderingContext.TEXTURE_2D_ARRAY:
                case WebGL2RenderingContext.TEXTURE_CUBE_MAP:
                case WebGL2RenderingContext.TEXTURE_2D: this.apply2DBase(texTarget, glTexture, texParam); break;
                default:
            }
        }
    }
}